﻿using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core.DAG;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using RapidSalesAdminPortalAPI.DataAccess;
using RapidSalesAdminPortalAPI.Models;
using RapidSalesAdminPortalAPI.Util;
using System.Security.Policy;
using WebAPI.Common;
using static WebAPI.Models.Enums;

namespace RapidSalesAdminPortalAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class PayController : ParentFrontController
    {
        private readonly RS_AdmPortalContext _context;
        private readonly IConfiguration _configuration;
        private readonly ILogUtility _logUtility;
        private readonly ILogger _logger;
        private readonly IDataProtectorUtility _dataProtectorUntility;

        public PayController(RS_AdmPortalContext context, IConfiguration configuration, ILogUtility logUtility, ILogger<ProductController> logger, IDataProtectorUtility dataProtectorUntility)
        {
            _context = context;
            _configuration = configuration;
            _logUtility = logUtility; // sample code for DI of common utility class
            _logger = logger;
            _dataProtectorUntility = dataProtectorUntility;
        }

        /// <summary>
        /// Get Pay Result
        /// </summary>
        /// <param name="requestModel"></param>
        /// <returns></returns>
        [HttpPost("GetPayResult")]
        public async Task<ActionResult<ResultMsg>> GetPayResult([FromBody] GetPayResultRequest requestModel)
        {
            var resultMsg = new ResultMsg();
            try
            {
                GetPayResultResponse res = new GetPayResultResponse();
                int result = 0;
                string msg = "";
                IQueryable<FrIpTransactionHistory> paComont = _context.FrIpTransactionHistories.AsQueryable();
                paComont = paComont.Where(x => x.OrderNo == requestModel.orderno);
                var paData = await paComont.ToListAsync();
                if (paData != null && paData.Count > 0)
                {
                    var status = paData.FirstOrDefault()?.TransactionStatus;
                    int.TryParse(status, out result);
                }

                switch (result)
                {
                    case 0:
                    case 10:
                        msg = "Pending Payment";
                        break;
                    case 11:
                        msg = "Payment overdue";
                        break;
                    case 12:
                        msg = "Payment cancel";
                        break;
                    case 20:
                        msg = "Payment in progress";
                        break;
                    case 30:
                        msg = "Payment successful";
                        break;
                    case 40:
                        msg = "Payment failed";
                        break;
                    default:
                        break;
                }

                res.result = result;
                res.msg = msg;

                //success return 
                return resultMsg.SetResultMsg(
                (int)ResultCode.Success,
                HelperUtility.GetDescription(ResultCode.Success),
                res);
            }
            catch (Exception ex)
            {
                _logger.LogError("Pay/GetPayResult Error:" + ex.Message);
                return resultMsg.SetResultMsg(
                 (int)ResultCode.ErrorOnRequestUnMarshalling,
                 HelperUtility.GetDescription(ResultCode.ErrorOnRequestUnMarshalling),
                 ex.Message);
            }
        }

        /// <summary>
        /// Get GetPayInfo
        /// </summary>
        /// <param name="requestModel"></param>
        /// <returns></returns>
        [HttpPost("GetPayInfo")]
        public async Task<ActionResult<ResultMsg>> GetPayInfo([FromBody] GetPayInfoRequest requestModel)
        {
            var resultMsg = new ResultMsg();
            try
            {
                var merchantId = _configuration["MerchantInfo:MerchantId"].ToString();
                //var orderNo = DateTime.Now.Ticks.ToString();
                //var secureHashSecret = _configuration["MerchantInfo:SecureHashSecret"].ToString();
                var secureHash = GenerateSecureHash(requestModel.orderNo, requestModel.paymentType, requestModel.currencyCode, requestModel.amount);

                GetPayInfoResponse res = new GetPayInfoResponse();
                res.merchantId = merchantId;
                res.secureHash = secureHash;

                //success return 
                return resultMsg.SetResultMsg(
                (int)ResultCode.Success,
                HelperUtility.GetDescription(ResultCode.Success),
                res);
            }
            catch (Exception ex)
            {
                _logger.LogError("Pay/GetPayResult Error:" + ex.Message);
                return resultMsg.SetResultMsg(
                 (int)ResultCode.ErrorOnRequestUnMarshalling,
                 HelperUtility.GetDescription(ResultCode.ErrorOnRequestUnMarshalling),
                 ex.Message);
            }
        }

        /// <summary>
        /// Payment interface callback 
        /// </summary>
        /// <param name="requestModel"></param>
        /// <returns></returns>
        [HttpPost("Callback")]
        public async Task<ActionResult<ResultMsg>> Callback([FromBody] CallbackRequest requestModel)
        {
            var resultMsg = new ResultMsg();
            try
            {
                CallbackResponse res = new CallbackResponse();
                var sourceData = JsonConvert.SerializeObject(requestModel);
                _logger.LogInformation("Pay/Callback request:" + sourceData);
                if (string.IsNullOrWhiteSpace(requestModel.Ref))
                {
                    return resultMsg.SetResultMsg(
                     (int)ResultCode.FieldRequired,
                     HelperUtility.GetDescription(ResultCode.FieldRequired),
                     "Ref is empty");
                }

                //verify datafeed
                var isOk = verifyDatafeed(requestModel.src.ToString(), requestModel.prc.ToString(), requestModel.successcode, requestModel.Ref, requestModel.PayRef, requestModel.Cur, requestModel.Amt, requestModel.payerAuth, requestModel.secureHash);
                if (!isOk)
                {
                    return resultMsg.SetResultMsg(
                     (int)ResultCode.VerifyDatafeedFailed,
                     HelperUtility.GetDescription(ResultCode.VerifyDatafeedFailed),
                     null);
                }

                //query transaction
                IQueryable<FrIpTransactionHistory> paComont = _context.FrIpTransactionHistories.AsQueryable();
                paComont = paComont.Where(x => x.OrderNo == requestModel.Ref);
                var paData = await paComont.ToListAsync();
                if (paData == null || paData.Count == 0 || paData.FirstOrDefault() == null)
                {
                    return resultMsg.SetResultMsg(
                     (int)ResultCode.NoDataFound,
                     HelperUtility.GetDescription(ResultCode.NoDataFound),
                     null);
                }
                var model = paData.FirstOrDefault();

                //check status
                int status = 0;
                var transactionStatus = model?.TransactionStatus;
                int.TryParse(transactionStatus, out status);
                if (status != (int)TransactionStatusType.Paymented)
                {
                    return resultMsg.SetResultMsg(
                     (int)ResultCode.Unpayment,
                     HelperUtility.GetDescription(ResultCode.Unpayment),
                     null);
                }

                //update entity
                var now = DateTime.Now;
                model.LastUpdatedOn = now;
                model.DataFeedReceivedOn = now;
                model.DataFeedSourceData = sourceData;
                model.DataFeedTransactionTime = now;
                model.DataFeedResults = requestModel.successcode;
                model.DataFeedPaymentRef = requestModel.Ref;
                model.DataFeedPayDollarPaymentRef = requestModel.PayRef;
                model.DataFeedBankRef = requestModel.Ord;
                model.DataFeedAmount = requestModel.Amt.ToString();
                model.DataFeedPaymentMethod = requestModel.payMethod;
                model.DataFeedAlertCode = requestModel.AlertCode;
                _context.Entry(model).State = EntityState.Modified;
                await _context.SaveChangesAsync();

                //success return 
                return resultMsg.SetResultMsg(
                (int)ResultCode.Success,
                HelperUtility.GetDescription(ResultCode.Success),
                res);
            }
            catch (Exception ex)
            {
                _logger.LogError("Pay/Callback Error:" + ex.Message);
                return resultMsg.SetResultMsg(
                 (int)ResultCode.ErrorOnRequestUnMarshalling,
                 HelperUtility.GetDescription(ResultCode.ErrorOnRequestUnMarshalling),
                 ex.Message);
            }
        }

        /// <summary>
        /// Generate SecureHash
        /// </summary>
        /// <param name="orderNo"></param>
        /// <param name="paymentType"></param>
        /// <param name="currencyCode"></param>
        /// <param name="amount"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private string GenerateSecureHash(string orderNo, string paymentType, string currencyCode, decimal amount)
        {
            try
            {
                var merchantId = _configuration["MerchantInfo:MerchantId"].ToString();
                var secureHashSecret = _configuration["MerchantInfo:SecureHashSecret"].ToString();

                string str = merchantId + "|" + orderNo + "|" + currencyCode + "|" + amount + "|" + paymentType + "|" + secureHashSecret;
                var data = SHA1Helper.Encrypt(str);

                return data;
            }
            catch (Exception ex)
            {
                _logger.LogError("Pay/GenerateSecureHash Error:" + ex.Message);
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// verify Datafeed
        /// </summary>
        /// <param name="src"></param>
        /// <param name="prc"></param>
        /// <param name="successCode"></param>
        /// <param name="orderNo"></param>
        /// <param name="payRef"></param>
        /// <param name="currencyCode"></param>
        /// <param name="amount"></param>
        /// <param name="payerAuth"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private bool verifyDatafeed(string src, string prc, string successCode, string orderNo, string payRef, string currencyCode, decimal amount, string payerAuth, string secureHash)
        {
            try
            {
                //var merchantId = _configuration["MerchantInfo:MerchantId"].ToString();
                var secureHashSecret = _configuration["MerchantInfo:SecureHashSecret"].ToString();

                string str = src + "|" + prc + "|" + successCode + "|" + orderNo + "|" + payRef + "|" + currencyCode + "|" + amount + "|" + payerAuth + "|" + secureHashSecret;
                var data = SHA1Helper.Encrypt(str);

                return secureHash.ToLower() == data.ToLower();
            }
            catch (Exception ex)
            {
                _logger.LogError("Pay/GenerateSecureHash Error:" + ex.Message);
                throw new Exception(ex.Message);
            }
        }

    }
}
